﻿function pieChart(chartId, chartDataSelector) {

    // Config settings
    var chartSizePercent = 100;                        // The chart radius relative to the canvas width/height (in percent)
    var sliceBorderWidth = 1;                         // Width (in pixels) of the border around each slice
    var sliceBorderStyle = "#fff";                    // Colour of the border around each slice
    var pullOutShadowColour = "rgba( 0, 0, 0, .5 )";  // Colour to use for the pull-out slice shadow
    var pullOutBorderWidth = 2;                       // Width (in pixels) of the pull-out slice border
    var pullOutBorderStyle = "#333";                  // Colour of the pull-out slice border
    var chartStartAngle = -.5 * Math.PI;              // Start the chart at 12 o'clock instead of 3 o'clock

    // Declare some variables for the chart
    var canvas;                       // The canvas element in the page
    var currentToolTipSlice = -1;     // The slice currently pulled out (-1 = no slice)
    var chartData = [];               // Chart data (labels, values, and angles)
    var chartColours = [];            // Chart colours (pulled from the HTML table)
    var totalValue = 0;               // Total of all the values in the chart
    var canvasWidth;                  // Width of the canvas, in pixels
    var canvasHeight;                 // Height of the canvas, in pixels
    var centreX;                      // X-coordinate of centre of the canvas/chart
    var centreY;                      // Y-coordinate of centre of the canvas/chart
    var chartRadius;                  // Radius of the pie chart, in pixels

    // Set things up and draw the chart
    init();


    /**
    * Set up the chart data and colours, as well as the chart and table click handlers,
    * and draw the initial pie chart
    */

    function init() {

        // Get the canvas element in the page
        canvas = document.getElementById(chartId);

        // Exit if the browser isn't canvas-capable
        if (typeof canvas.getContext === 'undefined') return;

        // Initialise some properties of the canvas and chart
        canvasWidth = canvas.width;
        canvasHeight = canvas.height;
        centreX = canvasWidth / 2;
        centreY = canvasHeight / 2;
        chartRadius = Math.min(canvasWidth, canvasHeight) / 2 * (chartSizePercent / 100);

        // Grab the data from the table,
        // and assign click handlers to the table data cells

        var currentRow = -1;
        var currentCell = 0;

        $(chartDataSelector + ' td').each(function () {
            currentCell++;
            if (currentCell % 2 != 0) {
                currentRow++;
                chartData[currentRow] = [];
                chartData[currentRow]['label'] = $(this).text();
            } else {
                var value = parseFloat($(this).text());
                totalValue += value;
                value = value.toFixed(2);
                chartData[currentRow]['value'] = value;
            }

            // Store the slice index in this cell, and attach a click handler to it
            $(this).data('slice', currentRow);

            // Extract and store the cell colour
            chartColours[currentRow] = {
                stop0: extractColor($(this).parent(), 'background-color'),
                stop1: extractColor(this, 'color')
            };
        });

        // Now compute and store the start and end angles of each slice in the chart data

        var currentPos = 0; // The current position of the slice in the pie (from 0 to 1)

        for (var slice in chartData) {
            chartData[slice]['startAngle'] = 2 * Math.PI * currentPos;
            chartData[slice]['endAngle'] = 2 * Math.PI * (currentPos + (chartData[slice]['value'] / totalValue));
            chartData[slice]['percentage'] = (chartData[slice]['value'] / totalValue) * 100;
            currentPos += chartData[slice]['value'] / totalValue;
        }

        // All ready! Now draw the pie chart, and add the click handler to it
        drawChart();
        $('#chart').mousemove(handleMouseMove);
    }

    function extractColor(obj, cssReference) {
        var colorValue;
        var rgb;
        var hex;
        debug("extractColor(" + $(obj) + ", " + cssReference + ")");
        debug($(obj).css(cssReference));
        if (rgb = $(obj).css(cssReference).match(/rgb\((\d+), (\d+), (\d+)/)) {
            colorValue = [rgb[1], rgb[2], rgb[3]];
        } else if (hex = $(obj).css(cssReference).match(/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/)) {
            colorValue = [parseInt(hex[1], 16), parseInt(hex[2], 16), parseInt(hex[3], 16)];
        } else {
            alert("Error: Colour could not be determined! Please specify table colours using the format '#xxxxxx'");
            return null;
        }
        
        return colorValue;
    }
    
    
    /**
    * Process mouse clicks in the chart area.
    *
    * If a slice was clicked, toggle it in or out.
    * If the user clicked outside the pie, push any slices back in.
    *
    * @param Event The mouseover event
    */
    function handleMouseMove(eventArgs) {

        // Get the mouse cursor position at the time of the mouseover, relative to the canvas
        var mouseX = eventArgs.pageX - this.offsetLeft;
        var mouseY = eventArgs.pageY - this.offsetTop;
        
        
        // Was the click inside the pie chart?
        var xFromCentre = mouseX - centreX;
        var yFromCentre = mouseY - centreY;
        var distanceFromCentre = Math.sqrt(Math.pow(Math.abs(xFromCentre), 2) + Math.pow(Math.abs(yFromCentre), 2));

        if (distanceFromCentre <= chartRadius) {

            
            
            // Yes, the click was inside the chart.
            // Find the slice that was clicked by comparing angles relative to the chart centre.

            var clickAngle = Math.atan2(yFromCentre, xFromCentre) - chartStartAngle;
            if (clickAngle < 0) clickAngle = 2 * Math.PI + clickAngle;

            for (var slice in chartData) {
                if (clickAngle >= chartData[slice]['startAngle'] && clickAngle <= chartData[slice]['endAngle']) {

                    // Slice found. show the tool tip.
                    showSliceTooltip(slice, mouseX, mouseY);
                    return;
                }
            }
        }

        // User must have clicked outside the pie. Push any pulled-out slice back in.
        hideAllTooltips();
    }


    /**
    * Push a slice in or out.
    *
    * If it's already pulled out, push it in. Otherwise, pull it out.
    *
    * @param Number The slice index (between 0 and the number of slices - 1)
    */

    function showSliceTooltip(slice, x, y) {
        if (slice != currentToolTipSlice) {
            showTooltip(slice, x, y);
        }
    }


    /**
    * show the tooltip for a slice
    *
    * @param Number The slice index (between 0 and the number of slices - 1)
    */

    function showTooltip(slice, x, y) {
        return;

        // Exit if we're already pulling out this slice
        if (currentToolTipSlice == slice) return;

        // Record the slice that we're pulling out, clear any previous animation, then start the animation
        debugObj(chartData[slice]);

        currentToolTipSlice = slice;

        var tooltip = $('#tooltip');
        tooltip.hide();
        tooltip.empty();
        tooltip.append('<span class="tooltipLabel">' + chartData[slice].label + '</span><br>');
        tooltip.append('<span class="tooltipAmount">' + chartData[slice].value + ' GB</span>');
        tooltip.append(' <span class="tooltipPercentage">(' + (chartData[slice].percentage).toFixed(2) + '%)</span>');
        tooltip.css('left', x);
        tooltip.css('top', y);
        tooltip.show();
        
    }

    /**
    * Push any pulled-out slice back in.
    *
    * Resets the animation variables and redraws the chart.
    * Also un-highlights all rows in the table.
    */

    function hideAllTooltips() {
        currentToolTipSlice = -1;
        drawChart();
        $("#tooltip").hide();
    }


    /**
    * Draw the chart.
    *
    * Loop through each slice of the pie, and draw it.
    */

    function drawChart() {

        // Get a drawing context
        var context = canvas.getContext('2d');

        // Clear the canvas, ready for the new frame
        context.clearRect(0, 0, canvasWidth, canvasHeight);

        // Draw each slice of the chart, skipping the pull-out slice (if any)
        for (var slice in chartData) {
            if (slice != currentToolTipSlice) drawSlice(context, slice);
        }

        // If there's a pull-out slice in effect, draw it.
        // (We draw the pull-out slice last so its drop shadow doesn't get painted over.)
        if (currentToolTipSlice != -1) drawSlice(context, currentToolTipSlice);
    }


    /**
    * Draw an individual slice in the chart.
    *
    * @param Context A canvas context to draw on  
    * @param Number The index of the slice to draw
    */

    function drawSlice(context, slice) {

        // Compute the adjusted start and end angles for the slice
        var startAngle = chartData[slice]['startAngle'] + chartStartAngle;
        var endAngle = chartData[slice]['endAngle'] + chartStartAngle;

        var startX = centreX;
        var startY = centreY;

        // Set up the gradient fill for the slice
        var sliceGradient = context.createLinearGradient(0, 0, canvasWidth * .75, canvasHeight * .75);
        sliceGradient.addColorStop(0, 'rgb(' + chartColours[slice].stop0.join(',') + ')');
        sliceGradient.addColorStop(1, 'rgb(' + chartColours[slice].stop1.join(',') + ')');

        // Draw the slice
        context.beginPath();
        context.moveTo(startX, startY);
        context.arc(startX, startY, chartRadius, startAngle, endAngle, false);
        context.lineTo(startX, startY);
        context.closePath();
        context.fillStyle = sliceGradient;
        context.shadowColor = (slice == currentToolTipSlice) ? pullOutShadowColour : "rgba( 0, 0, 0, 0 )";
        context.fill();
        context.shadowColor = "rgba( 0, 0, 0, 0 )";

        // Style the slice border appropriately
        if (slice == currentToolTipSlice) {
            context.lineWidth = pullOutBorderWidth;
            context.strokeStyle = pullOutBorderStyle;
        } else {
            context.lineWidth = sliceBorderWidth;
            context.strokeStyle = sliceBorderStyle;
        }

        // Draw the slice border
        context.stroke();
    }
};
